﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.InteropServices;
using WindowsInput;
using Microsoft.Research.Kinect.Nui;
using System.IO;
using System.Timers;
using Microsoft.Research.Kinect.Audio;
using Microsoft.Speech.Recognition;
using Microsoft.Speech.AudioFormat;

namespace WpfApplication30
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        [DllImport("User32.dll")]
        private static extern int GetWindowText(IntPtr handle, StringBuilder text, int MaxLen);

        [DllImport("User32.dll")]
        private static extern IntPtr GetForegroundWindow();

        [DllImport("User32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);

        public MainWindow()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            //Thread.Sleep(3000);
            //for (int i = 0; i < 10; i++)
            //{
            //    StringBuilder text = new StringBuilder(1000);
            //    GetWindowText(GetForegroundWindow(), text, text.Capacity);
            //    if (text.ToString().Contains("VirtuaNES") == true)
            //    {
            //        InputSimulator.SimulateKeyDown(VirtualKeyCode.VK_D);

            //        InputSimulator.SimulateKeyDown(VirtualKeyCode.VK_K);
            //        Thread.Sleep(10);
            //        InputSimulator.SimulateKeyUp(VirtualKeyCode.VK_K);

            //        Thread.Sleep(2000);
            //        InputSimulator.SimulateKeyDown(VirtualKeyCode.VK_K);
            //        Thread.Sleep(10);
            //        InputSimulator.SimulateKeyUp(VirtualKeyCode.VK_K);
            //    }
            //}
        }

        private Cursor mouse;
        private Cursor click;

        private int screenWidth;
        private int screenHeight;
        private float maxX;
        private float maxY;

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.screenWidth = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
            this.screenHeight = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
            maxY = 0.5f;
            maxX = (screenWidth * maxY) / screenHeight;
            maxX = (float)Math.Round(maxX, 2);

            using (FileStream stream = new FileStream("Mouse.ani", FileMode.Open))
            {
                mouse = new Cursor(stream);
            }

            using (FileStream stream = new FileStream("Click.ani", FileMode.Open))
            {
                click = new Cursor(stream);
            }

            this.Cursor = mouse;
            this.timer = new Timer(3400);
            this.timer.AutoReset = false;
            this.timer.Elapsed += timer_Callback;

            nui = new Runtime();
            nui.Initialize(RuntimeOptions.UseSkeletalTracking);
            nui.SkeletonEngine.TransformSmooth = true;
            var parameters = new TransformSmoothParameters { Smoothing = 0.75f, Correction = 0.0f, Prediction = 0.0f, JitterRadius = 0.05f, MaxDeviationRadius = 0.04f };
            nui.SkeletonEngine.SmoothParameters = parameters;
            nui.SkeletonFrameReady += nui_SkeletonFrameReady;

            var t = new System.Threading.Thread(InitSpeechRecognization);
            t.Start();
        }

        private void InitSpeechRecognization()
        {
            audioSource = new KinectAudioSource();
            audioSource.FeatureMode = true;
            audioSource.AutomaticGainControl = false;
            audioSource.SystemMode = SystemMode.OptibeamArrayOnly;

            RecognizerInfo ri = SpeechRecognitionEngine.InstalledRecognizers().Where(r => r.Id == "SR_MS_en-US_Kinect_10.0").FirstOrDefault();
            recEngine = new SpeechRecognitionEngine(ri.Id);
            var colors = new Choices();
            colors.Add("shoot");
            colors.Add("select");
            colors.Add("start");

            var gb = new GrammarBuilder();
            gb.Culture = ri.Culture;
            gb.Append(colors);

            var g = new Grammar(gb);

            recEngine.LoadGrammar(g);
            recEngine.SpeechRecognized += SreSpeechRecognized;

            Stream s = audioSource.Start();
            recEngine.SetInputToAudioStream(s, new SpeechAudioFormatInfo(EncodingFormat.Pcm, 16000, 16, 1, 32000, 2, null));
            recEngine.RecognizeAsync(RecognizeMode.Multiple);
        }

        private void SreSpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            if (e.Result.Confidence > 0.9)
            {
                this.Dispatcher.BeginInvoke(new Action(() => { label3.Content = e.Result.Text; }));
                if (e.Result.Text == "select")
                {
                    InputSimulator.SimulateKeyDown(VirtualKeyCode.VK_Z);
                    System.Threading.Thread.Sleep(500);
                    InputSimulator.SimulateKeyUp(VirtualKeyCode.VK_Z);
                }
                if (e.Result.Text == "start")
                {
                    InputSimulator.SimulateKeyDown(VirtualKeyCode.VK_X);
                    System.Threading.Thread.Sleep(500);
                    InputSimulator.SimulateKeyUp(VirtualKeyCode.VK_X);
                }
            }
        }

        private void nui_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) 
        {
            SkeletonFrame allSkeletons = e.SkeletonFrame;
            SkeletonData skeleton = allSkeletons.Skeletons.Where(p => p.TrackingState == SkeletonTrackingState.Tracked).First();
            float x = skeleton.Joints[JointID.HandRight].Position.X;
            float y = skeleton.Joints[JointID.HandRight].Position.Y;
            

            if (x < 0)
            {
                x = 0;
            }
            else
            {
                if (x > maxX)
                {
                    x = maxX;
                }
            }

            if (y < 0)
            {
                y = 0;
            }
            else
            {
                if (y > maxY)
                {
                    y = maxY;
                }
            }

            int mouseX = (int)((x * screenWidth) / maxX);
            int mouseY = screenHeight - (int)((y * screenHeight) / maxY);

            label1.Content = mouseX.ToString();
            label2.Content = mouseY.ToString();

            System.Windows.Forms.Cursor.Position = new System.Drawing.Point(mouseX, mouseY);

            if (isReady == true)
            {
                float tempX = skeleton.Joints[JointID.FootRight].Position.X;
                float tempY = skeleton.Joints[JointID.Head].Position.Y;
                float tempZ = skeleton.Joints[JointID.FootRight].Position.Z;

                tempX = tempX - this.x;
                if (tempX > 0.3)
                {
                    label4.Content = "Right";
                }
                else
                {
                    if (tempX < -0.3)
                    {
                        label4.Content = "Left";
                    }
                    else
                    {
                        label4.Content = "O";
                    }
                }

                tempY = tempY - this.y;
                if (tempY > 0.15)
                {
                    label3.Content = "Jump";
                }
                else
                {
                    //label4.Content = "|O";
                }

                tempZ = this.z - tempZ;
                if (tempZ > 0.3)
                {
                    label4.Content += "|Up";
                }
                else
                {
                    if (tempZ < -0.3)
                    {
                        label4.Content += "|Down";
                    }
                    else
                    {
                        label4.Content += "|O";
                    }
                }

                // Game Control ////////////////////////
                StringBuilder text = new StringBuilder(1000);
                GetWindowText(GetForegroundWindow(), text, text.Capacity);
                if (text.ToString().Contains("VirtuaNES") == true)
                {
                    if (tempX > 0.3)
                    {
                        InputSimulator.SimulateKeyDown(VirtualKeyCode.VK_D);
                    }
                    else
                    {
                        if (tempX < -0.3)
                        {
                            InputSimulator.SimulateKeyDown(VirtualKeyCode.VK_A);
                        }
                        else
                        {
                            InputSimulator.SimulateKeyUp(VirtualKeyCode.VK_D);
                            InputSimulator.SimulateKeyUp(VirtualKeyCode.VK_A);
                        }
                    }

                    if (tempY > 0.15)
                    {
                        InputSimulator.SimulateKeyDown(VirtualKeyCode.VK_K);
                        System.Threading.Thread.Sleep(1000);
                        InputSimulator.SimulateKeyUp(VirtualKeyCode.VK_A);
                    }
                }
                ////////////////////////////////////////
            }
        }

        private Runtime nui;

        private KinectAudioSource audioSource;

        private SpeechRecognitionEngine recEngine;

        private Timer timer;

        private void button2_MouseEnter(object sender, MouseEventArgs e)
        {
            this.timer.Start();
            this.Cursor = click;
        }

        private void button2_MouseLeave(object sender, MouseEventArgs e)
        {
            this.timer.Stop();
            this.Cursor = mouse;
        }

        private void timer_Callback(object sender, ElapsedEventArgs e)
        {
            //this.Dispatcher.BeginInvoke(new Action(() => { label3.Content = DateTimeOffset.Now.Second.ToString(); this.Cursor = mouse; }));
            SkeletonFrame frame = nui.SkeletonEngine.GetNextFrame(1000);
            SkeletonData skeleton = frame.Skeletons.Where(p => p.TrackingState == SkeletonTrackingState.Tracked).First();
            this.x = skeleton.Joints[JointID.FootRight].Position.X;
            this.y = skeleton.Joints[JointID.Head].Position.Y;
            this.z = skeleton.Joints[JointID.FootRight].Position.Z;

            isReady = true;
            this.Dispatcher.BeginInvoke(new Action(() => { this.Cursor = mouse; }));

            System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName("VirtuaNES");
            if (processes.Length > 0)
            {
                SetForegroundWindow(processes[0].MainWindowHandle);
            }
        }

        private float z;
        private float x;
        private float y;

        private bool isReady;

        private void Window_Closed(object sender, EventArgs e)
        {
            nui.Uninitialize();
        }
    }
}
